#include <windows.h>
#include <tchar.h>

#include "ProcessInfo.h"

namespace platform {

void ProcessInfo::GetCurrentProcessExeName(XString &name) {
	LPTSTR strCommandLine = ::GetCommandLine();
	if (strCommandLine == NULL || strCommandLine[0] == _T('\0'))
		return;

	TCHAR chSep = _T(' ');
	if (strCommandLine[0] == _T('\'') || strCommandLine[0] == _T('\"')) {
		chSep = strCommandLine[0];
		strCommandLine++;
	}

	TCHAR * chFound = _tcschr(strCommandLine, chSep);
	if (chFound == NULL) {
		// return the whole string
		name = strCommandLine;
		return;
	}

	name = XString(strCommandLine, chFound - strCommandLine);
}

} // end namespace



//////////////////////////////////////////////////////
// GetThreadId function is supported only in Vista,
// for previous versions of windows a following
// (unsafe) method is used, as described in
// http://www.codeguru.com/forum/showthread.php?t=355572

typedef struct _CLIENT_ID
{
    DWORD UniqueProcess; 
    DWORD UniqueThread;
} CLIENT_ID, *PCLIENT_ID;

typedef LONG NTSTATUS;
#define STATUS_SUCCESS ((NTSTATUS) 0x00000000)

typedef LONG KPRIORITY;

typedef struct _THREAD_BASIC_INFORMATION
{
    NTSTATUS   ExitStatus;
    PVOID      TebBaseAddress;
    CLIENT_ID  ClientId;
    KAFFINITY  AffinityMask;
    KPRIORITY  Priority;
    KPRIORITY  BasePriority;
} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;

typedef enum _THREAD_INFORMATION_CLASS
{
    ThreadBasicInformation = 0
    //...
} THREAD_INFORMATION_CLASS, *PTHREAD_INFORMATION_CLASS;

typedef NTSTATUS (__stdcall *pfnNtQueryInformationThread) (HANDLE, THREAD_INFORMATION_CLASS, PVOID, ULONG, PULONG);


namespace platform {

HMODULE ProcessInfo::NtDllLoader::hm = NULL;
FARPROC ProcessInfo::NtDllLoader::fGetThreadInfo = 0;

DWORD ProcessInfo::GetThreadIdFromHandle(HANDLE h) {
	NtDllLoader ntdll;
	pfnNtQueryInformationThread ntQueryInfo = (pfnNtQueryInformationThread) ntdll.getFuncThreadInfo();
	if (ntQueryInfo == NULL) return 0;

    // use function
    THREAD_BASIC_INFORMATION tbi;
    THREAD_INFORMATION_CLASS tic = ThreadBasicInformation;
    if (ntQueryInfo(h, tic, &tbi, sizeof(tbi), NULL) != STATUS_SUCCESS)
        return 0;

    // print uniqe thread id
    return tbi.ClientId.UniqueThread;
}

}  // end namespace